use std::{
	collections::BTreeMap,
	path::{Path, PathBuf},
};

use super::*;

#[derive(Debug, Default, Clone)]
pub struct Layers {
	layers: BTreeMap<String, Layer>,
}
impl core::ops::Deref for Layers {
	type Target = BTreeMap<String, Layer>;
	fn deref(&self) -> &Self::Target {
		&self.layers
	}
}
impl Layers {
	pub fn parse(r: &mut Parser<'_, '_, '_>, base: impl AsRef<Path>) -> Result<Self, Error> {
		struct Pair(String, String);
		impl FromPlist for Pair {
			fn from_plist(r: &mut Parser<'_, '_, '_>) -> Result<Self, Error> {
				Ok(Pair(r.string()?, r.string()?))
			}
		}
		let data: Vec<Vec<Pair>> = r.read()?;
		let base = base.as_ref();
		let mut this = Self::default();
		for v in data {
			for Pair(k, v) in v {
				this.layers.insert(k, Self::load_layer(base.join(v))?);
			}
		}
		Ok(this)
	}
	pub fn load_layer(dir: PathBuf) -> Result<Layer, Error> {
		let content = std::fs::read_to_string(dir.join(CONTENTS_FILE)).map_err(Error::from)?;
		let mut xml = xml::Parser::new(&content);
		let contents = Contents::parse(&mut Parser(&mut plist::Parser::new(&mut xml).peekable()), dir.clone()) //
			.map_err(Error::from)?;
		let info = if let Ok(content) = std::fs::read_to_string(dir.join(LAYER_INFO_FILE)) {
			let mut xml = xml::Parser::new(&content);
			Value::from_plist(&mut Parser(&mut plist::Parser::new(&mut xml).peekable()))?
		} else {
			Default::default()
		};
		Ok(Layer { dir, contents, info })
	}
	pub fn sure_default(&mut self, base: impl AsRef<Path>) -> Result<(), Error> {
		if !self.layers.contains_key(DEFAULT_LAYER_NAME) {
			self.layers.insert(
				DEFAULT_LAYER_NAME.to_string(),
				Self::load_layer(base.as_ref().join(DEFAULT_GLYPHS_DIR))?,
			);
		}
		Ok(())
	}
}

#[derive(Debug, Default, Clone)]
pub struct Layer {
	pub dir: PathBuf,
	pub contents: Contents,
	pub info: Value,
}

#[derive(Debug, Default, Clone)]
pub struct Contents {
	glyphs: BTreeMap<String, PathBuf>,
}
impl core::ops::Deref for Contents {
	type Target = BTreeMap<String, PathBuf>;
	fn deref(&self) -> &Self::Target {
		&self.glyphs
	}
}
impl Contents {
	pub fn parse(r: &mut Parser<'_, '_, '_>, base: PathBuf) -> Result<Self, Error> {
		r.dict_start()?;
		let mut this = Self::default();
		loop {
			match r.next()? {
				plist::Event::End => break,
				plist::Event::Error(e, _) => return Err(Error::Plist(e)),
				plist::Event::Key(key) => {
					this.glyphs.insert(key.to_string(), base.join(r.string()?));
				}
				_ => return Err(Error::Msg("expect key")),
			}
		}
		Ok(this)
	}
}
